﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;

namespace HGPFramework.Design
{
    public class HGPButton : Button
    {
        #region Fields

        private MouseState MState = MouseState.None;
        private Theme thm = Theme.MSOffice2010_BLUE;

        private enum MouseState
        {
            None = 1,
            Down = 2,
            Up = 3,
            Enter = 4,
            Leave = 5,
            Move = 6
        }

        #endregion

        #region Constructor

        public HGPButton()
        {
            SetStyle(ControlStyles.SupportsTransparentBackColor |
                     ControlStyles.Opaque |
                     ControlStyles.ResizeRedraw |
                     ControlStyles.OptimizedDoubleBuffer |
                     ControlStyles.CacheText, // We gain about 2% in painting by avoiding extra GetWindowText calls
                true);

            colorTable = new Colortable();

            MouseLeave += _MouseLeave;
            MouseDown += _MouseDown;
            MouseUp += _MouseUp;
            MouseMove += _MouseMove;
        }

        #endregion

        #region Events

        #region Paint Transparent Background

        protected void PaintTransparentBackground(Graphics g, Rectangle clipRect)
        {
            // check if we have a parent
            if (Parent != null)
            {
                // convert the clipRects coordinates from ours to our parents
                clipRect.Offset(Location);

                var e = new PaintEventArgs(g, clipRect);

                // save the graphics state so that if anything goes wrong 
                // we're not fubar
                GraphicsState state = g.Save();

                try
                {
                    // move the graphics object so that we are drawing in 
                    // the correct place
                    g.TranslateTransform(-Location.X, -Location.Y);

                    // draw the parents background and foreground
                    InvokePaintBackground(Parent, e);
                    InvokePaint(Parent, e);

                    return;
                }
                finally
                {
                    // reset everything back to where they were before
                    g.Restore(state);
                    clipRect.Offset(-Location.X, -Location.Y);
                }
            }

            // we don't have a parent, so fill the rect with
            // the default control color
            g.FillRectangle(SystemBrushes.Control, clipRect);
        }

        #endregion

        #region Mouse Events

        private void _MouseDown(object sender, MouseEventArgs mevent)
        {
            MState = MouseState.Down;
            Invalidate();
        }

        private void _MouseUp(object sender, MouseEventArgs mevent)
        {
            MState = MouseState.Up;
            Invalidate();
        }

        private void _MouseMove(object sender, MouseEventArgs mevent)
        {
            MState = MouseState.Move;
            Invalidate();
        }

        private void _MouseLeave(object sender, EventArgs e)
        {
            MState = MouseState.Leave;
            Invalidate();
        }

        #endregion

        #region Path

        public static GraphicsPath GetRoundedRect(RectangleF r, float radius)
        {
            var gp = new GraphicsPath();
            gp.StartFigure();
            r = new RectangleF(r.Left, r.Top, r.Width, r.Height);
            if (radius <= 0.0F || radius <= 0.0F)
            {
                gp.AddRectangle(r);
            }
            else
            {
                gp.AddArc(r.X, r.Y, radius, radius, 180, 90);
                gp.AddArc(r.Right - radius, r.Y, radius - 1, radius, 270, 90);
                gp.AddArc(r.Right - radius, r.Bottom - radius - 1, radius - 1, radius, 0, 90);
                gp.AddArc(r.X, r.Bottom - radius - 1, radius - 1, radius, 90, 90);
            }
            gp.CloseFigure();
            return gp;
        }

        #endregion

        protected override void OnPaint(PaintEventArgs e)
        {
            PaintTransparentBackground(e.Graphics, ClientRectangle);

            #region Painting

            //now let's we begin painting
            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

            #endregion

            #region Color

            Color tTopColorBegin = colorTable.ButtonNormalColor1;
            Color tTopColorEnd = colorTable.ButtonNormalColor2;
            Color tBottomColorBegin = colorTable.ButtonNormalColor3;
            Color tBottomColorEnd = colorTable.ButtonNormalColor4;
            Color Textcol = colorTable.TextColor;


            if (!Enabled)
            {
                tTopColorBegin = Color.FromArgb((int) (tTopColorBegin.GetBrightness()*255),
                    (int) (tTopColorBegin.GetBrightness()*255),
                    (int) (tTopColorBegin.GetBrightness()*255));
                tBottomColorEnd = Color.FromArgb((int) (tBottomColorEnd.GetBrightness()*255),
                    (int) (tBottomColorEnd.GetBrightness()*255),
                    (int) (tBottomColorEnd.GetBrightness()*255));
            }
            else
            {
                if (MState == MouseState.None || MState == MouseState.Leave)
                {
                    tTopColorBegin = colorTable.ButtonNormalColor1;
                    tTopColorEnd = colorTable.ButtonNormalColor2;
                    tBottomColorBegin = colorTable.ButtonNormalColor3;
                    tBottomColorEnd = colorTable.ButtonNormalColor4;
                    Textcol = colorTable.TextColor;
                }
                else if (MState == MouseState.Down)
                {
                    tTopColorBegin = colorTable.ButtonSelectedColor1;
                    tTopColorEnd = colorTable.ButtonSelectedColor2;
                    tBottomColorBegin = colorTable.ButtonSelectedColor3;
                    tBottomColorEnd = colorTable.ButtonSelectedColor4;
                    Textcol = colorTable.SelectedTextColor;
                }
                else if (MState == MouseState.Move || MState == MouseState.Up)
                {
                    tTopColorBegin = colorTable.ButtonMouseOverColor1;
                    tTopColorEnd = colorTable.ButtonMouseOverColor2;
                    tBottomColorBegin = colorTable.ButtonMouseOverColor3;
                    tBottomColorEnd = colorTable.ButtonMouseOverColor4;
                    Textcol = colorTable.HoverTextColor;
                }
            }

            #endregion

            #region Theme 2010

            if (thm == Theme.MSOffice2010_BLUE || thm == Theme.MSOffice2010_Green || thm == Theme.MSOffice2010_Yellow ||
                thm == Theme.MSOffice2010_Publisher ||
                thm == Theme.MSOffice2010_RED || thm == Theme.MSOffice2010_WHITE || thm == Theme.MSOffice2010_Pink)
            {
                Paint2010Background(e, g, tTopColorBegin, tTopColorEnd, tBottomColorBegin, tBottomColorEnd);
                TEXTandIMAGE(ClientRectangle, g, Textcol);
            }

            #endregion
        }

        #region Paint 2010 Background

        protected void Paint2010Background(PaintEventArgs e, Graphics g, Color tTopColorBegin, Color tTopColorEnd,
            Color tBottomColorBegin, Color tBottomColorEnd)
        {
            int _roundedRadiusX = 6;

            var r = new Rectangle(ClientRectangle.Left, ClientRectangle.Top, ClientRectangle.Width,
                ClientRectangle.Height);
            Rectangle j = r;
            Rectangle r2 = r;
            r2.Inflate(-1, -1);
            Rectangle r3 = r2;
            r3.Inflate(-1, -1);

            //rectangle for gradient, half upper and lower
            var halfup = new RectangleF(r.Left, r.Top, r.Width, r.Height);
            var halfdown = new RectangleF(r.Left, r.Top + (r.Height/2) - 1, r.Width, r.Height);

            //BEGIN PAINT BACKGROUND
            //for half upper, we paint using linear gradient
            using (GraphicsPath thePath = GetRoundedRect(r, _roundedRadiusX))
            {
                var lgb = new LinearGradientBrush(halfup, tBottomColorEnd, tBottomColorBegin, 90f, true);

                var blend = new Blend(4);
                blend.Positions = new[] {0, 0.18f, 0.35f, 1f};
                blend.Factors = new[] {0f, .4f, .9f, 1f};
                lgb.Blend = blend;
                g.FillPath(lgb, thePath);
                lgb.Dispose();

                //for half lower, we paint using radial gradient
                using (var p = new GraphicsPath())
                {
                    p.AddEllipse(halfdown); //make it radial
                    using (var gradient = new PathGradientBrush(p))
                    {
                        gradient.WrapMode = WrapMode.Clamp;
                        gradient.CenterPoint = new PointF(Convert.ToSingle(halfdown.Left + halfdown.Width/2),
                            Convert.ToSingle(halfdown.Bottom));
                        gradient.CenterColor = tBottomColorEnd;
                        gradient.SurroundColors = new[] {tBottomColorBegin};

                        blend = new Blend(4);
                        blend.Positions = new[] {0, 0.15f, 0.4f, 1f};
                        blend.Factors = new[] {0f, .3f, 1f, 1f};
                        gradient.Blend = blend;

                        g.FillPath(gradient, thePath);
                    }
                }
                //END PAINT BACKGROUND

                //BEGIN PAINT BORDERS
                using (GraphicsPath gborderDark = thePath)
                {
                    using (var p = new Pen(tTopColorBegin, 1))
                    {
                        g.DrawPath(p, gborderDark);
                    }
                }
                using (GraphicsPath gborderLight = GetRoundedRect(r2, _roundedRadiusX))
                {
                    using (var p = new Pen(tTopColorEnd, 1))
                    {
                        g.DrawPath(p, gborderLight);
                    }
                }
                using (GraphicsPath gborderMed = GetRoundedRect(r3, _roundedRadiusX))
                {
                    var bordermed = new SolidBrush(Color.FromArgb(50, tTopColorEnd));
                    using (var p = new Pen(bordermed, 1))
                    {
                        g.DrawPath(p, gborderMed);
                    }
                }
                //END PAINT BORDERS
            }
        }

        #endregion

        #region Paint TEXT AND IMAGE

        protected void TEXTandIMAGE(Rectangle Rec, Graphics g, Color textColor)
        {
            //BEGIN PAINT TEXT
            var sf = new StringFormat();
            sf.Alignment = StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;

            #region Top

            if (TextAlign == ContentAlignment.TopLeft)
            {
                sf.LineAlignment = StringAlignment.Near;
                sf.Alignment = StringAlignment.Near;
            }
            else if (TextAlign == ContentAlignment.TopCenter)
            {
                sf.LineAlignment = StringAlignment.Near;
                sf.Alignment = StringAlignment.Center;
            }
            else if (TextAlign == ContentAlignment.TopRight)
            {
                sf.LineAlignment = StringAlignment.Near;
                sf.Alignment = StringAlignment.Far;
            }

                #endregion

                #region Middle

            else if (TextAlign == ContentAlignment.MiddleLeft)
            {
                sf.LineAlignment = StringAlignment.Center;
                sf.Alignment = StringAlignment.Near;
            }
            else if (TextAlign == ContentAlignment.MiddleCenter)
            {
                sf.LineAlignment = StringAlignment.Center;
                sf.Alignment = StringAlignment.Center;
            }
            else if (TextAlign == ContentAlignment.MiddleRight)
            {
                sf.LineAlignment = StringAlignment.Center;
                sf.Alignment = StringAlignment.Far;
            }

                #endregion

                #region Bottom

            else if (TextAlign == ContentAlignment.BottomLeft)
            {
                sf.LineAlignment = StringAlignment.Far;
                sf.Alignment = StringAlignment.Near;
            }
            else if (TextAlign == ContentAlignment.BottomCenter)
            {
                sf.LineAlignment = StringAlignment.Far;
                sf.Alignment = StringAlignment.Center;
            }
            else if (TextAlign == ContentAlignment.BottomRight)
            {
                sf.LineAlignment = StringAlignment.Far;
                sf.Alignment = StringAlignment.Far;
            }

            #endregion

            if (ShowKeyboardCues)
                sf.HotkeyPrefix = HotkeyPrefix.Show;
            else
                sf.HotkeyPrefix = HotkeyPrefix.Hide;
            g.DrawString(Text, Font, new SolidBrush(textColor), Rec, sf);
        }

        #endregion

        #endregion

        #region Properties

        #region ColorTable

        private Colortable colorTable;

        [DefaultValue(typeof (Colortable), "Office2010Blue")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Colortable ColorTable
        {
            get
            {
                if (colorTable == null)
                    colorTable = new Colortable();

                return colorTable;
            }
            set
            {
                if (value == null)
                    value = Colortable.Office2010Blue;

                colorTable = value;

                Invalidate();
            }
        }

        public Theme Theme
        {
            get
            {
                if (colorTable == Colortable.Office2010Green)
                {
                    return Theme.MSOffice2010_Green;
                }
                if (colorTable == Colortable.Office2010Red)
                {
                    return Theme.MSOffice2010_RED;
                }
                if (colorTable == Colortable.Office2010Pink)
                {
                    return Theme.MSOffice2010_Pink;
                }
                if (colorTable == Colortable.Office2010Yellow)
                {
                    return Theme.MSOffice2010_Yellow;
                }
                if (colorTable == Colortable.Office2010White)
                {
                    return Theme.MSOffice2010_WHITE;
                }
                if (colorTable == Colortable.Office2010Publisher)
                {
                    return Theme.MSOffice2010_Publisher;
                }

                return Theme.MSOffice2010_BLUE;
            }

            set
            {
                thm = value;

                if (thm == Theme.MSOffice2010_Green)
                {
                    colorTable = Colortable.Office2010Green;
                }
                else if (thm == Theme.MSOffice2010_RED)
                {
                    colorTable = Colortable.Office2010Red;
                }
                else if (thm == Theme.MSOffice2010_Pink)
                {
                    colorTable = Colortable.Office2010Pink;
                }
                else if (thm == Theme.MSOffice2010_WHITE)
                {
                    colorTable = Colortable.Office2010White;
                }
                else if (thm == Theme.MSOffice2010_Yellow)
                {
                    colorTable = Colortable.Office2010Yellow;
                }
                else if (thm == Theme.MSOffice2010_Publisher)
                {
                    colorTable = Colortable.Office2010Publisher;
                }
                else
                {
                    colorTable = Colortable.Office2010Blue;
                }
            }
        }

        #endregion

        #region Background Image

        [Browsable(false)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        public override ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        #endregion

        #endregion
    }
}